home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / PowerPlant / LMouser 2.2 / LMouser.cp next >
Encoding:
Text File  |  1996-06-30  |  10.3 KB  |  409 lines  |  [TEXT/CWIE]

  1. /*
  2.     LMouser is © 1996 Boxes Objects Links Design Pty Ltd.  All Rights Reserved. 
  3.     You use this software at your own risk, etc. Permission is given to Timothy C.
  4.     Delaney to use LMouser. Permission is given for all others to use LMouser if
  5.     acknowledgement of this copyright is given in publically-released software.
  6.     Acknowledgement should consist of a statement equivalent to "Sections of this
  7.     program are © Boxes Objects Links Design Pty Ltd", visible in an "About..." box
  8.     or splash screen.
  9.                                                                                         */
  10.  
  11. /*
  12.     LMouser 2.2
  13.  
  14.     Release data:    31/5/96
  15.  
  16.     LMouser is a mix-in class (like LListener) for using the MouseEnter(), MouseLeave()
  17.     and MouseWithin() methods of an LPane.
  18.  
  19.     Revision History:
  20.     
  21.     2.2
  22.     
  23.     Discovered that LView::FindDeepSubMouserContaining() would return an invisible
  24.     pane, preventing an LMouser behind it from receiving any events. I found this
  25.     one all by myself... A new function LMouser::FindVisibleDeepSubPaneContaining()
  26.     is now part of the package.
  27.     
  28.     2.1
  29.     
  30.     Fixed a logical error which got introduced somewhere after 1.0: only LMousers in
  31.     the active window would respond. This has been removed. Thanks to Daniel Sears
  32.     for pointing this out.
  33.     
  34.     2.0
  35.     
  36.     Fixed a bug which could result in a crash if the mouse is inside a mouser when
  37.     that mouser is destroyed. This might account for a number of crashes I was
  38.     getting in my other code. Thanks Bill Hubauer.
  39.     
  40.     Made LMouseDispatcher internal to LMouser.cp (and hence invisible to the rest of
  41.     the world). LMouseDispatcher now inherits from LPeriodical and installs an
  42.     instance of itself as a repeater with StartRepeating(). As a side effect,
  43.     LMousers are now dealt with *after* events are dispatched (when AdjustCursor()
  44.     in the application class was being overridden they were being dealt with
  45.     beforehand). The application class now no longer (and indeed cannot) inherit
  46.     from LMouseDispatcher.
  47.     
  48.     1.1
  49.     
  50.     Split LMouser into two classes: LMouser and LMouseDispatcher. The application
  51.     class is to inherit from LMouseDispatcher. Used, but never released.
  52.     
  53.     1.0
  54.     
  55.     First release.
  56.                                                                                          */
  57.  
  58. #include <Windows.h>
  59.  
  60. #include <LPane.h>
  61. #include "LMouser.h"
  62. #include <LPeriodical.h>
  63. #include <LWindow.h>
  64. #include <LArray.h>
  65.  
  66. #pragma RTTI on
  67.  
  68. LMouser    *LMouser::sLastMouser    = NULL;
  69. LPane    *LMouser::sLastPane        = NULL,
  70.         *LMouser::sCurrentPane    = NULL;
  71.  
  72. class LMouseDispatcher : private LMouser, public LPeriodical
  73. {
  74.     public:
  75.  
  76.                             LMouseDispatcher (void    );
  77.         virtual                ~LMouseDispatcher (void    );
  78.  
  79.         virtual void        SpendTime (const EventRecord    &inMacEvent                        );
  80.  
  81.         virtual LMouser *    GetSuperMouser (void                                            );
  82.  
  83.         static LMouseDispatcher *    GetMouseDispatcher (void                                );
  84.  
  85.         void                AddMouser (LMouser    *theMouser                                    );
  86.  
  87.         void                RemoveMouser (LMouser    *theMouser                                );
  88.  
  89.     private:
  90.  
  91.         static LMouseDispatcher    sMouseDispatcher;
  92.         static LArray            sMousers;
  93.  
  94.         virtual LMouser *    FindDeepSubMouserContaining (const EventRecord    &inMacEvent        );
  95.         virtual LMouser *    FindShallowSubMouserContaining (const EventRecord    &inMacEvent    );
  96.  
  97. };
  98.  
  99. LMouseDispatcher    LMouseDispatcher::sMouseDispatcher;
  100. LArray                LMouseDispatcher::sMousers(sizeof(LMouser *));
  101.  
  102. LMouser::LMouser (void    )
  103. {
  104.     mSuperMouser = NULL;
  105.  
  106.     if (this != LMouseDispatcher::GetMouseDispatcher())
  107.     {
  108.         LMouseDispatcher::GetMouseDispatcher()->AddMouser(this);
  109.     }
  110. }
  111.  
  112. LMouser::~LMouser (void    )
  113. {
  114.     if (this == sLastMouser)
  115.     {
  116.         sLastMouser = NULL;
  117.         sLastPane = NULL;
  118.     }
  119.  
  120.     if (this != LMouseDispatcher::GetMouseDispatcher())
  121.     {
  122.         LMouseDispatcher::GetMouseDispatcher()->RemoveMouser(this);
  123.     }
  124. }
  125.  
  126. /*
  127.     LPane::FindDeepSubPaneContaining() will return an invisible pane: not what we want. So
  128.     we will create our own function which returns the deepest *visible* subpane.
  129.                                                                                                 */
  130.  
  131. LPane *    LMouser::FindVisibleDeepSubPaneContaining (Int32    inHorizPort,
  132.                                                    Int32    inVertPort,
  133.                                                    LPane    *startPane    )
  134. {
  135.     LView    *startView    = dynamic_cast<LView *>(startPane);
  136.  
  137.     LPane            *hitSubPane    = startPane;
  138.  
  139.     if (startView)
  140.     {
  141.         LListIterator    iterator(startView->GetSubPanes(), iterate_FromEnd);
  142.         LPane            *theSub;
  143.         
  144.         while (iterator.Previous(&theSub))
  145.         {
  146.             if (theSub->IsVisible() && theSub->Contains(inHorizPort, inVertPort))
  147.             {
  148.                 hitSubPane = FindVisibleDeepSubPaneContaining(inHorizPort, inVertPort, theSub);
  149.                 break;
  150.             }
  151.         }
  152.     }
  153.     
  154.     return hitSubPane;
  155. }
  156.  
  157. /*
  158.     LMouser::FindDeepSubMouserContaining() corresponds to LPane::FindDeepSubPaneContaining()
  159.     This function takes an optional LPane * parameter. This is because not every pane is an
  160.     LMouser - if the application (for example) is finding the deepest LMouser it can, it must
  161.     be able to find it whether or not the window containing the mouse point is an LMouser.
  162.                                                                                                 */
  163.  
  164. LMouser *    LMouser::FindDeepSubMouserContaining (Int32        inHorizPort,
  165.                                                   Int32        inVertPort,
  166.                                                   LPane *    startPane        )
  167. {
  168.     LPane            *tempPane    = NULL;
  169.     LMouser            *mouserHit    = NULL;
  170.  
  171.     mouserHit = NULL;
  172.  
  173.     if (!startPane)
  174.     {
  175.         startPane = dynamic_cast<LPane *>(this);
  176.     }
  177.  
  178.     if (startPane)
  179.     {
  180.         tempPane = //startPane->FindDeepSubPaneContaining(inHorizPort, inVertPort);
  181.                    FindVisibleDeepSubPaneContaining(inHorizPort, inVertPort, startPane);
  182.  
  183.         if (tempPane)
  184.         {
  185.             startPane = tempPane;
  186.         }
  187.     }
  188.  
  189.     while (startPane && (!mouserHit || !tempPane->IsEnabled()))
  190.     {
  191.         mouserHit = dynamic_cast<LMouser *>(startPane);
  192.         tempPane = startPane;
  193.         startPane = (LPane *) startPane->GetSuperView();
  194.     }
  195.  
  196.     return mouserHit;
  197. }
  198.  
  199. /*
  200.     LMouser::FindShallowSubMouserContaining() corresponds to LPane::FindShallowSubPaneContaining()
  201.     This function takes an optional LPane * parameter. This is because not every pane is an
  202.     LMouser - if the application (for example) is finding the shallowest LMouser it can, it must
  203.     be able to find it whether or not the window containing the mouse point is an LMouser.
  204.                                                                                                 */
  205.  
  206. LMouser *    LMouser::FindShallowSubMouserContaining (Int32        inHorizPort,
  207.                                                      Int32        inVertPort,
  208.                                                      LPane *    startPane        )
  209. {
  210.     LMouser    *mouserHit    = NULL;
  211.  
  212.     mouserHit = NULL;
  213.  
  214.     if (!startPane)
  215.     {
  216.         startPane = dynamic_cast<LPane *>(this);
  217.     }
  218.  
  219.     LPane    *tempPane    = NULL;
  220.  
  221.     while (startPane && (!mouserHit || !tempPane->IsEnabled()))
  222.     {
  223.         mouserHit = dynamic_cast<LMouser *>(startPane);
  224.         tempPane = startPane;
  225.         startPane = startPane->FindShallowSubPaneContaining(inHorizPort, inVertPort);
  226.     }
  227.  
  228.     return mouserHit;
  229. }
  230.  
  231. /*
  232.     Rather than storing the supermouser as a field, simply go up the list of SuperViews of the
  233.     current LMouser (LPane) until we find another LMouser or we run out. The application, even
  234.     though it must be an LMouser, is never the SuperMouser of an LMouser.
  235.                                                                                                 */
  236.  
  237. LMouser *    LMouser::GetSuperMouser (void    )
  238. {
  239.     LPane    *curPane = dynamic_cast<LPane *>(this);
  240.  
  241.     mSuperMouser = NULL;
  242.  
  243.     while (curPane && !mSuperMouser)
  244.     {
  245.         curPane = (LPane *) curPane->GetSuperView();
  246.         mSuperMouser = dynamic_cast<LMouser *>(curPane);
  247.     }
  248.  
  249.     return mSuperMouser;
  250. }
  251.  
  252. LPane *    LMouser::GetLastPane (void    )
  253. {
  254.     return sLastPane;
  255. }
  256.  
  257. LPane *    LMouser::GetCurrentPane (void    )
  258. {
  259.     return sCurrentPane;
  260. }
  261.  
  262. /*
  263.     If the currently hit LMouser is different to the previous LMouser, call the MouseLeave()
  264.     function for the LMouser (which is an LPane). Then call the MouseEnter() function for the
  265.     new LMouser. If the mouse didn't change mousers then call the MouseWithin() function.
  266.  
  267.     This function does not pass unused mouse events to the SuperMouser - if a pane/mouser wants
  268.     to do this it must be done inside the MouseLeave(), MouseEnter() and MouseWithin()
  269.     functions. It is assumed that an LMouser will deal with all three mouse events.
  270.                                                                                                 */
  271.  
  272. LMouseDispatcher::LMouseDispatcher (void    )
  273. {
  274.     StartRepeating();
  275. }
  276.  
  277. LMouseDispatcher::~LMouseDispatcher (void    )
  278. {
  279. }
  280.  
  281. LMouseDispatcher *    LMouseDispatcher::GetMouseDispatcher (void    )
  282. {
  283.     return &sMouseDispatcher;
  284. }
  285.  
  286. void    LMouseDispatcher::AddMouser (LMouser    *theMouser    )
  287. {
  288.     if (theMouser && sMousers.FetchIndexOf(&theMouser) == LArray::index_Bad)
  289.     {
  290.         sMousers.InsertItemsAt(1, LArray::index_Last, &theMouser);
  291.     }
  292. }
  293.  
  294. void    LMouseDispatcher::RemoveMouser (LMouser    *theMouser    )
  295. {
  296.     if (theMouser)
  297.     {
  298.         sMousers.Remove(&theMouser);
  299.     }
  300. }
  301.  
  302. void    LMouseDispatcher::SpendTime (const EventRecord    &inMacEvent    )
  303. {
  304.     sLastPane = sCurrentPane;
  305.     sLastMouser = dynamic_cast<LMouser *>(sLastPane);
  306.     sCurrentPane = NULL;
  307.  
  308.     if (sMousers.GetCount() == 0)
  309.     {
  310.         return;
  311.     }
  312.  
  313.     Point    portMouse        = inMacEvent.where;
  314.  
  315.     LMouser    *mouserHit        = NULL;
  316.  
  317.     Boolean    mouserChanged;
  318.  
  319.     mouserHit = FindDeepSubMouserContaining(inMacEvent);
  320.     sCurrentPane = dynamic_cast<LPane *>(mouserHit);
  321.     mouserChanged = sLastPane != sCurrentPane;
  322.  
  323.     if (sLastPane && mouserChanged)
  324.     {
  325.         sLastPane->MouseLeave();
  326.     }
  327.  
  328.     if (sCurrentPane)
  329.     {
  330.         sCurrentPane->GlobalToPortPoint(portMouse);
  331.  
  332.         if (mouserChanged)
  333.         {
  334.             sCurrentPane->MouseEnter(portMouse, inMacEvent);
  335.         }
  336.         else
  337.         {
  338.             sCurrentPane->MouseWithin(portMouse, inMacEvent);
  339.         }
  340.     }
  341. }
  342.  
  343. /*
  344.     When only an event record is given it is still possible to find the deepest LMouser -
  345.     first the correct window needs to be found, then the correct subpane can be found.
  346.                                                                                                 */
  347.  
  348. LMouser *    LMouseDispatcher::FindDeepSubMouserContaining (const EventRecord    &inMacEvent    )
  349. {
  350.     WindowPtr    macWindowP;
  351.     Point        globalMouse    = inMacEvent.where;
  352.     LMouser        *mouserHit    = NULL;
  353.  
  354.     short        thePart        = ::FindWindow(globalMouse, &macWindowP);
  355.     LWindow        *theWindow    = LWindow::FetchWindowObject(macWindowP);
  356.  
  357.     if ((theWindow != NULL) && theWindow->IsEnabled())
  358.     {
  359.         theWindow->GlobalToPortPoint(globalMouse);
  360.         mouserHit = LMouser::FindDeepSubMouserContaining(globalMouse.h, globalMouse.v, theWindow);
  361.     }
  362.     else
  363.     {
  364.         mouserHit = NULL;
  365.     }
  366.  
  367.     return mouserHit;
  368. }
  369.  
  370. /*
  371.     When only an event record is given it is still possible to find the shallowest LMouser -
  372.     first the correct window needs to be found, then the correct subpane can be found.
  373.                                                                                                 */
  374.  
  375. LMouser *    LMouseDispatcher::FindShallowSubMouserContaining (const EventRecord    &inMacEvent    )
  376. {
  377.     WindowPtr    macWindowP;
  378.     Point        globalMouse    = inMacEvent.where;
  379.     LMouser        *mouserHit    = NULL;
  380.  
  381.     ::FindWindow(globalMouse, &macWindowP);
  382.  
  383.     LWindow        *theWindow = LWindow::FetchWindowObject(macWindowP);
  384.  
  385.     if ((theWindow != nil) && theWindow->IsEnabled())
  386.     {
  387.         theWindow->GlobalToPortPoint(globalMouse);
  388.         mouserHit = LMouser::FindShallowSubMouserContaining(globalMouse.h, globalMouse.v, theWindow);
  389.  
  390.         if (!mouserHit)
  391.         {
  392.             mouserHit = dynamic_cast<LMouser *>(theWindow);
  393.         }
  394.     }
  395.     else
  396.     {
  397.         mouserHit = NULL;
  398.     }
  399.  
  400.     return mouserHit;
  401. }
  402.  
  403. LMouser *    LMouseDispatcher::GetSuperMouser (void    )
  404. {
  405.     return NULL;
  406. }
  407.  
  408. #pragma RTTI reset
  409.